
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';

import 'FormValidate.dart';

Map<String, dynamic> filterTextFieldRules(BuildContext context, FormControlContext controlContext) {
    FormCreatorHandler formHandler = FormCreatorState.of(context);
    String errorText = formHandler.validateResult.field == controlContext.field && !formHandler.validateResult.validate ? formHandler.validateResult.msg : null;
    List<TextInputFormatter> inputFormatters = <TextInputFormatter>[];

    int maxLength = formHandler.rules?.firstWhere((item){
      return item.max != null && item.field == controlContext.field;
    }, orElse: ()=> null)?.max;

    return <String, dynamic>{
      "errorText": errorText,
      "inputFormatters": inputFormatters,
      "maxLength": maxLength,
    };
 }


class FormControlContext {
  final String field;
  final dynamic value;
  final bool autoValidate;
  final Map<String, dynamic> defaultProps;
  final Map<String, dynamic> props;
  final BuildContext context;


  FormControlContext({ this.context, this.defaultProps, this.props, this.field, this.value, this.autoValidate = false});

  Map<String, dynamic> get mergedProps {
    Map<String, dynamic> _mergedProps = <String, dynamic>{};
    props?.forEach((key, value) {
      _mergedProps.putIfAbsent(key, ()=> value);
    });
    defaultProps?.forEach((key, value) {
      _mergedProps.putIfAbsent(key, ()=> value);
    });
    try {
      filterTextFieldRules(context, this)?.forEach((key, value) {
      _mergedProps.putIfAbsent(key, ()=> value);
    });
    } catch (e) {
      // firstWhere 可能会报错
    }
    return _mergedProps;
  }

  FormControlContext copyWith({ defaultProps, props, field, value, autoValidate, context }) {
    return FormControlContext(
      defaultProps: defaultProps ?? this.defaultProps,
      props: props ??= this.props,
      field: field ??= this.field,
      value: value ??= this.value,
      autoValidate: autoValidate ??= this.autoValidate,
      context: context ??= this.context,
    );
  }
}

class FormCreatorContext {
  final Map<String,dynamic> formData;
  final List<ValidateRule> rules;
  final ValidateResult validateResult;
  final FormControlContext controlContext;

  FormCreatorContext({this.formData, this.rules, this.validateResult, this.controlContext});
}

typedef void FormControlChangeCallback(FormControlContext context);
typedef Future FormCreatorChangeCallback(FormCreatorContext context);
typedef void FormCreatorFieldsChangeCallback(FormCreatorField field, List<FormCreatorField> fields);
typedef Widget FormControlBuilder(FormControlContext context);

class FormCreatorField {
  final String field;
  final String type;
  bool autoValidate;
  Map<String, dynamic> defaultProps = <String, dynamic>{};
  Map<String, dynamic> props = <String, dynamic>{};

  FormCreatorField({ this.type = "text", @required this.field,this.props, this.defaultProps, this.autoValidate });
}

class FormCreator extends StatefulWidget {
  final Map<String,dynamic> formData;
  final List<ValidateRule> rules;
  final ValidateResult validateResult;
  final List<FormCreatorField> fields;
  final Map<String, FormControlBuilder> controls;
  /// 表单状态更改过后返回回调 可以在上一层调用
  final FormCreatorChangeCallback onChange;
  /// 验证通过过后自动调用提交
  final FormCreatorChangeCallback onSubmit;
  /// 返回验证结果 validateResult
  final FormCreatorChangeCallback onValidate;
  /// 配置参数发生变化
  final FormCreatorFieldsChangeCallback onFieldsChange;

  FormCreator({Key key, this.formData, @required this.fields, this.validateResult, this.rules, this.onChange, this.onSubmit, this.onValidate, @required this.controls, this.onFieldsChange}) : super(key: key);

  @override
  FormCreatorState createState() => FormCreatorState();
}

class FormCreatorFieldBuilder extends StatelessWidget {
  final FormCreatorField child;
  final FormCreator parent;
  final Map<String, dynamic> formData;

  const FormCreatorFieldBuilder({Key key, this.parent, this.formData, this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if(parent.controls[child.type] != null) {
        FormControlBuilder builder = parent.controls[child.type];
        dynamic value = formData[child.field];
        return builder(FormControlContext(
        value: value, 
        defaultProps: child.defaultProps ??= <String, dynamic>{}, 
        props: child.props ??= <String, dynamic>{}, 
        field: child.field,
        autoValidate: child.autoValidate ??= false,
        context: context,
        ));
      }
      return null;
  }
}

class FormCreatorState extends State<FormCreator> {
  Map<String,dynamic> formData = <String,dynamic>{}; 
  List<ValidateRule> rules = [];
  ValidateResult validateResult = ValidateResult.fromRule(validate: true);

  static FormCreatorHandler of(BuildContext context){
    return context.dependOnInheritedWidgetOfExactType<FormCreatorHandler>();
  }

  @override
  void initState() { 
    super.initState();
    formData = widget.formData ?? <String,dynamic>{};
    rules = widget.rules ?? [];
    validateResult = widget.validateResult ?? ValidateResult.fromRule(validate: true);
  }

  @override
  Widget build(BuildContext context) {    
    return FormCreatorHandler(
       formData: formData,
       rules: rules,
       validateResult: validateResult,
       child: Column(
         children: widget.fields.map((FormCreatorField child){
           return FormCreatorFieldBuilder(child: child, formData: formData, parent: widget);
         }).where((item) => item!=null).toList()
       ),
       onChange: (FormCreatorContext context) async {
         if(widget.onChange!=null) {
           await widget.onChange(context);
         }
         setState((){
           formData = context.formData;
         });
       },
       onSubmit: (FormCreatorContext context) async {
         if(widget.onSubmit != null) {
           await widget.onSubmit(context);
         }
         setState((){
           formData = context.formData;
         });
       },
       onValidate: (FormCreatorContext context) async {
         if(widget.onValidate != null) {
           await widget.onValidate(context);
         }
         setState((){
           validateResult = context.validateResult;
         });
       },
       onFieldControlChange: (FormControlContext context) {
         int index =  widget.fields.indexWhere((item)=> item.field == context.field);
         if(index == -1) return;
         FormCreatorField formField = widget.fields[index];
         if(formField==null) return;
         if(formField.defaultProps != context.defaultProps && context.defaultProps != null) formField.defaultProps = context.defaultProps;
         if(formField.props != context.props && context.props != null) formField.props = context.props;
         if(formField.autoValidate != context.autoValidate && context.autoValidate != null) formField.autoValidate = context.autoValidate;
         widget.fields[index] = formField;
         widget.onFieldsChange(formField, widget.fields);
       }
    );
  }
}

class FormCreatorHandler extends InheritedWidget {
  final Map<String,dynamic> formData;
  final List<ValidateRule> rules;
  final ValidateResult validateResult;
    /// 表单状态更改过后返回回调 可以在上一层调用
  final FormCreatorChangeCallback onChange;
  /// 验证通过过后自动调用提交
  final FormCreatorChangeCallback onSubmit;
  /// 返回验证结果 validateResult
  final FormCreatorChangeCallback onValidate;
  /// 配置参数发生变化
  final FormControlChangeCallback onFieldControlChange;
  /// 组件配置参数变化
  void changeFieldControl(FormControlContext context) {
    assert(context.field !=null, "使用changeFieldControl方法传递的上下文中必须包含field");
    if(onFieldControlChange!=null) {
      onFieldControlChange(context);
    }
  }
  /// 更改内容
  void changeValue(FormControlContext context) {
    formData[context.field] = context.value;
    if(onChange != null) {
      onChange(FormCreatorContext(
        formData: formData,
        controlContext: context
      ));
    }
    if(context.autoValidate) {
      validateOne(context.field);
    }
  }
  /// 提交内容
  void submit() async {
    if(await validate() && onSubmit != null) {
      onSubmit(FormCreatorContext(
        formData: formData,
      ));
    }
  }
  /// 验证所有内容
  Future<bool> validate() async {
    return await validateAll();
  }
  /// 验证单个字段内容
  Future<bool> validateOne(String field) async {
    Validator validator = new Validator(rules);
    ValidateResult validateResult = await validator.validateOne(field, formData);
    emitValidateCallback(validateResult);
    return validateResult.validate;
  }
  /// 验证所有内容
  Future<bool> validateAll() async {
    Validator validator = new Validator(rules);
    ValidateResult validateResult = await validator.validateAll(formData, null);
    emitValidateCallback(validateResult);
    return validateResult.validate;
  }
  /// 触发验证
  void emitValidateCallback(ValidateResult validateResult) {
    if(onValidate != null) {
      onValidate(FormCreatorContext(
        validateResult: validateResult,
      ));
    }
  }

  FormCreatorHandler({ this.onChange, this.onSubmit, this.onValidate, @required this.formData, this.rules, this.validateResult, Widget child, this.onFieldControlChange}): super(child: child);

  @override
  bool updateShouldNotify(FormCreatorHandler oldWidget) {
    return true;
  }
}